//
//  ControllerLayer.cpp
//  NinjaTurtle
//
//  Created by Nguyen Tri Chung on 1/30/15.
//
//

#include "ControllerLayer.h"

ControllerLayer::ControllerLayer(View* gameScene) {
    this->gameScene = gameScene;
    Size winSize = Director::getInstance()->getWinSize();
    this->keyMap = new char[(int) winSize.width * (int) winSize.height];
    memset(this->keyMap, MOVE_KEY_NONE, (int) winSize.width * (int) winSize.height);
    this->savedTouches = new Map<Touch*, __Integer*>();
    this->initialize();
    this->autorelease();
}

ControllerLayer::~ControllerLayer() {
    this->_eventDispatcher->removeEventListener(this->touchListener);
    CC_SAFE_DELETE(this->savedTouches);
    delete this->keyMap;
}

void ControllerLayer::initialize() {
    this->touchListener = EventListenerTouchAllAtOnce::create();
    this->touchListener->onTouchesBegan = CC_CALLBACK_2(ControllerLayer::onTouchesBegan, this);
    this->touchListener->onTouchesMoved = CC_CALLBACK_2(ControllerLayer::onTouchesMoved, this);
    this->touchListener->onTouchesEnded = CC_CALLBACK_2(ControllerLayer::onTouchesEnded, this);
    this->touchListener->onTouchesCancelled = CC_CALLBACK_2(ControllerLayer::onTouchesEnded, this);
    this->_eventDispatcher->addEventListenerWithSceneGraphPriority(this->touchListener, this);
    
    this->createLayers();
    this->createLayersContent();
}

void ControllerLayer::createLayers() {
}

void ControllerLayer::createLayersContent() {
    Size winSize = Director::getInstance()->getWinSize();
    this->buttonLeft = new CSprite();
    this->buttonLeft->initWithSpriteFrameName(FRAME_BUTTON_LEFT);
    this->buttonLeft->setPosition(Point(150, 50) + Point(-CONFIG_RANGE_TO_MOVE, 0));
    this->buttonLeft->setOpacity(100);
    this->addChild(this->buttonLeft);
    
    this->buttonRight = new CSprite();
    this->buttonRight->initWithSpriteFrameName(FRAME_BUTTON_RIGHT);
    this->buttonRight->setPosition(Point(150, 50));
    this->buttonRight->setOpacity(100);
    this->addChild(this->buttonRight);
    
    this->buttonA = new CSprite();
    this->buttonA->initWithSpriteFrameName(FRAME_BUTTON_A);
    this->buttonA->setPosition(Point(winSize.width - 150, 50));
    this->buttonA->setOpacity(100);
    this->addChild(this->buttonA);
    
    this->buttonB = new CSprite();
    this->buttonB->initWithSpriteFrameName(FRAME_BUTTON_B);
    this->buttonB->setPosition(Point(winSize.width - 150 + CONFIG_RANGE_TO_MOVE, 50));
    this->buttonB->setOpacity(100);
    this->addChild(this->buttonB);
    
    this->buttonC = new CSprite();
    this->buttonC->initWithSpriteFrameName(FRAME_BUTTON_C);
    this->buttonC->setPosition(Point(winSize.width - 150 + CONFIG_RANGE_TO_MOVE, 50 + CONFIG_RANGE_TO_MOVE));
    this->buttonC->setOpacity(100);
    this->buttonC->setVisible(false);
    this->addChild(this->buttonC);
    
    {
        int width = CONFIG_RANGE_TO_MOVE;
        int height = CONFIG_RANGE_TO_MOVE;
        
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                Point parentRoot = this->buttonLeft->getPosition() - Point(width / 2, height / 2);
                Point realPoint = Point(j, height - i) + parentRoot;
                int h = realPoint.y;
                int w = realPoint.x;
                this->keyMap[h * (int) winSize.width + w] = MOVE_KEY_LEFT;
            }
        }
    }
    {
        int width = CONFIG_RANGE_TO_MOVE;
        int height = CONFIG_RANGE_TO_MOVE;
        
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                Point parentRoot = this->buttonRight->getPosition() - Point(width / 2, height / 2);
                Point realPoint = Point(j, height - i) + parentRoot;
                int h = realPoint.y;
                int w = realPoint.x;
                this->keyMap[h * (int) winSize.width + w] = MOVE_KEY_RIGHT;
            }
        }
    }
    {
        int width = this->buttonA->getContentSize().width;
        int height = this->buttonA->getContentSize().height;
        
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                Point parentRoot = this->buttonA->getPosition() - Point(width / 2, height / 2);
                Point realPoint = Point(j, height - i) + parentRoot;
                int h = realPoint.y;
                int w = realPoint.x;
                this->keyMap[h * (int) winSize.width + w] = TOUCH_KEY_A;
            }
        }
    }
    {
        int width = this->buttonB->getContentSize().width;
        int height = this->buttonB->getContentSize().height;
        
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                Point parentRoot = this->buttonB->getPosition() - Point(width / 2, height / 2);
                Point realPoint = Point(j, height - i) + parentRoot;
                int h = realPoint.y;
                int w = realPoint.x;
                this->keyMap[h * (int) winSize.width + w] = TOUCH_KEY_B;
            }
        }
    }
    {
        int width = this->buttonC->getContentSize().width;
        int height = this->buttonC->getContentSize().height;
        
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                Point parentRoot = this->buttonC->getPosition() - Point(width / 2, height / 2);
                Point realPoint = Point(j, height - i) + parentRoot;
                int h = realPoint.y;
                int w = realPoint.x;
                this->keyMap[h * (int) winSize.width + w] = TOUCH_KEY_C;
            }
        }
    }
}

void ControllerLayer::update(float dt) {
}

void ControllerLayer::onTouchesBegan(const std::vector<Touch*>& touches, Event* event) {
    this->checkTouchComeIn(touches);
}

void ControllerLayer::onTouchesMoved(const std::vector<Touch*>& touches, Event* event) {
    this->checkTouchComeIn(touches);
    this->checkTouchComeOut(touches);
}

void ControllerLayer::onTouchesEnded(const std::vector<Touch*>& touches, Event* event) {
    this->checkTouchComeOutAndRelease(touches);
}

void ControllerLayer::onTouchesCancelled(const std::vector<Touch*>& touches, Event* event) {
}

void ControllerLayer::checkTouchComeIn(const std::vector<Touch*>& touches) {
    int numberTouchLeft = 0;
    int numberTouchRight = 0;
    bool touchA = false;
    bool touchB = false;
    bool touchC = false;
    bool touchLeft = false;
    bool touchRight = false;
    
    Size winSize = Director::getInstance()->getWinSize();
    for (auto touch : touches) {
        Point point = this->convertTouchToNodeSpace(touch);
        char touchValue = this->keyMap[(int) point.y * (int) winSize.width + (int) point.x];
        
        if (touchValue == TOUCH_KEY_A && this->buttonA->getOpacity() == 100) {
            touchA = true;
        } else if (touchValue == TOUCH_KEY_B && this->buttonB->getOpacity() == 100) {
            touchB = true;
        } else if (touchValue == TOUCH_KEY_C && this->buttonC->getOpacity() == 100) {
            touchC = true;
        } else if (touchValue == MOVE_KEY_LEFT) {
            numberTouchLeft++;
        } else if (touchValue == MOVE_KEY_RIGHT) {
            numberTouchRight++;
        }
        
        this->savedTouches->insert(touch, __Integer::create(touchValue));
    }
    
    if (numberTouchLeft > numberTouchRight) {
        touchLeft = true;
    } else {
        touchRight = true;
    }
    
    if (numberTouchLeft == 0) {
        touchLeft = false;
    }
    
    if (numberTouchRight == 0) {
        touchRight = false;
    }
    
    if (touchA) {
        this->buttonA->setOpacity(255);
        
        GameEvent* gameEvent = new GameEvent();
        gameEvent->setEventCode(EVT_EQUIP);
        this->gameScene->fireEvent(gameEvent);
    }
    
    if (touchB) {
        this->buttonB->setOpacity(255);
        
        GameEvent* gameEvent = new GameEvent();
        gameEvent->setEventCode(EVT_JUMP);
        this->gameScene->fireEvent(gameEvent);
    }
    
    
    if (touchC) {
        this->buttonC->setOpacity(255);
        
        GameEvent* gameEvent = new GameEvent();
        gameEvent->setEventCode(EVT_FIRE);
        this->gameScene->fireEvent(gameEvent);
    }
    
    if (touchLeft) {
        this->buttonLeft->setOpacity(255);
        this->buttonRight->setOpacity(100);
        
        GameEvent* gameEvent = new GameEvent();
        gameEvent->setEventCode(EVT_GO_LEFT);
        this->gameScene->fireEvent(gameEvent);
    }
    
    if (touchRight) {
        this->buttonRight->setOpacity(255);
        this->buttonLeft->setOpacity(100);
        
        GameEvent* gameEvent = new GameEvent();
        gameEvent->setEventCode(EVT_GO_RIGHT);
        this->gameScene->fireEvent(gameEvent);
    }
}

void ControllerLayer::checkTouchComeOut(const std::vector<Touch*>& touches) {
    bool remainA = false;
    bool remainB = false;
    bool remainC = false;
    bool remainLeft = false;
    bool remainRight = false;
    
    vector<Touch*> allTouchs = this->savedTouches->keys();
    for (int i = 0; i < allTouchs.size(); i++) {
        Touch* touch = allTouchs.at(i);
        int touchValue = this->savedTouches->at(touch)->getValue();
        
        if (touchValue == TOUCH_KEY_A) {
            remainA = true;
        } else if (touchValue == TOUCH_KEY_B) {
            remainB = true;
        } else if (touchValue == TOUCH_KEY_C) {
            remainC = true;
        } else if (touchValue == MOVE_KEY_LEFT) {
            remainLeft = true;
        } else if (touchValue == MOVE_KEY_RIGHT) {
            remainRight = true;
        }
    }
    
    if (!remainA) {
        this->buttonA->setOpacity(100);
    }
    
    if (!remainB) {
        this->buttonB->setOpacity(100);
    }
    
    if (!remainC) {
        this->buttonC->setOpacity(100);
    }
    
    if (!remainLeft) {
        this->buttonLeft->setOpacity(100);
    }
    
    if (!remainRight) {
        this->buttonRight->setOpacity(100);
    }
    
    if (!remainLeft && !remainRight) {
        GameEvent* gameEvent = new GameEvent();
        gameEvent->setEventCode(EVT_GO_NONE);
        this->gameScene->fireEvent(gameEvent);
    }
}

void ControllerLayer::checkTouchComeOutAndRelease(const std::vector<Touch*>& touches) {
    bool remainA = false;
    bool remainB = false;
    bool remainC = false;
    bool remainLeft = false;
    bool remainRight = false;
    
    for (auto touch : touches) {
        this->savedTouches->erase(touch);
    }
    
    vector<Touch*> allTouchs = this->savedTouches->keys();
    for (int i = 0; i < allTouchs.size(); i++) {
        Touch* touch = allTouchs.at(i);
        int touchValue = this->savedTouches->at(touch)->getValue();
        
        if (touchValue == TOUCH_KEY_A) {
            remainA = true;
        } else if (touchValue == TOUCH_KEY_B) {
            remainB = true;
        } else if (touchValue == TOUCH_KEY_C) {
            remainC = true;
        } else if (touchValue == MOVE_KEY_LEFT) {
            remainLeft = true;
        } else if (touchValue == MOVE_KEY_RIGHT) {
            remainRight = true;
        }
    }
    
    if (!remainA) {
        this->buttonA->setOpacity(100);
    }
    
    if (!remainB) {
        this->buttonB->setOpacity(100);
    }
    
    if (!remainC) {
        this->buttonC->setOpacity(100);
    }
    
    if (!remainLeft) {
        this->buttonLeft->setOpacity(100);
    }
    
    if (!remainRight) {
        this->buttonRight->setOpacity(100);
    }
    
    if (!remainLeft && !remainRight) {
        GameEvent* gameEvent = new GameEvent();
        gameEvent->setEventCode(EVT_GO_NONE);
        this->gameScene->fireEvent(gameEvent);
    }
}